Public Class updater
    Inherits System.Windows.Forms.Form

#Region " Windows Form Designer generated code "

    Public Sub New()
        MyBase.New()

        'This call is required by the Windows Form Designer.
        InitializeComponent()

        'Add any initialization after the InitializeComponent() call

    End Sub

    'Form overrides dispose to clean up the component list.
    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
        If disposing Then
            If Not (components Is Nothing) Then
                components.Dispose()
            End If
        End If
        MyBase.Dispose(disposing)
    End Sub

    'Required by the Windows Form Designer
    Private components As System.ComponentModel.IContainer

    'NOTE: The following procedure is required by the Windows Form Designer
    'It can be modified using the Windows Form Designer.  
    'Do not modify it using the code editor.
    Friend WithEvents ColumnHeader1 As System.Windows.Forms.ColumnHeader
    Friend WithEvents ColumnHeader2 As System.Windows.Forms.ColumnHeader
    Friend WithEvents StatusImageList As System.Windows.Forms.ImageList
    Friend WithEvents ProgressBar As System.Windows.Forms.ProgressBar
    Friend WithEvents Timer As System.Windows.Forms.Timer
    Friend WithEvents updatesListview As System.Windows.Forms.ListView
    Friend WithEvents message As System.Windows.Forms.TextBox
    Friend WithEvents StatusBar1 As System.Windows.Forms.StatusBar
    Friend WithEvents infopanel As System.Windows.Forms.StatusBarPanel
    Friend WithEvents statusbarpanel As System.Windows.Forms.StatusBarPanel
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        Me.components = New System.ComponentModel.Container()
        Dim ListViewItem1 As System.Windows.Forms.ListViewItem = New System.Windows.Forms.ListViewItem(New String() {"updates.xml", "/"}, -1, System.Drawing.SystemColors.WindowText, System.Drawing.SystemColors.Window, New System.Drawing.Font("Microsoft Sans Serif", 8.25!, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, CType(0, Byte)))
        Dim resources As System.Resources.ResourceManager = New System.Resources.ResourceManager(GetType(updater))
        Me.updatesListview = New System.Windows.Forms.ListView()
        Me.ColumnHeader1 = New System.Windows.Forms.ColumnHeader()
        Me.ColumnHeader2 = New System.Windows.Forms.ColumnHeader()
        Me.StatusImageList = New System.Windows.Forms.ImageList(Me.components)
        Me.ProgressBar = New System.Windows.Forms.ProgressBar()
        Me.message = New System.Windows.Forms.TextBox()
        Me.Timer = New System.Windows.Forms.Timer(Me.components)
        Me.StatusBar1 = New System.Windows.Forms.StatusBar()
        Me.infopanel = New System.Windows.Forms.StatusBarPanel()
        Me.statusbarpanel = New System.Windows.Forms.StatusBarPanel()
        CType(Me.infopanel, System.ComponentModel.ISupportInitialize).BeginInit()
        CType(Me.statusbarpanel, System.ComponentModel.ISupportInitialize).BeginInit()
        Me.SuspendLayout()
        '
        'updatesListview
        '
        Me.updatesListview.Columns.AddRange(New System.Windows.Forms.ColumnHeader() {Me.ColumnHeader1, Me.ColumnHeader2})
        Me.updatesListview.Dock = System.Windows.Forms.DockStyle.Bottom
        Me.updatesListview.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable
        Me.updatesListview.Items.AddRange(New System.Windows.Forms.ListViewItem() {ListViewItem1})
        Me.updatesListview.LargeImageList = Me.StatusImageList
        Me.updatesListview.Location = New System.Drawing.Point(0, 52)
        Me.updatesListview.Name = "updatesListview"
        Me.updatesListview.Size = New System.Drawing.Size(314, 96)
        Me.updatesListview.SmallImageList = Me.StatusImageList
        Me.updatesListview.TabIndex = 0
        Me.updatesListview.View = System.Windows.Forms.View.Details
        '
        'ColumnHeader1
        '
        Me.ColumnHeader1.Text = "Filename"
        Me.ColumnHeader1.Width = 122
        '
        'ColumnHeader2
        '
        Me.ColumnHeader2.Text = "Folder"
        Me.ColumnHeader2.Width = 174
        '
        'StatusImageList
        '
        Me.StatusImageList.ColorDepth = System.Windows.Forms.ColorDepth.Depth8Bit
        Me.StatusImageList.ImageSize = New System.Drawing.Size(16, 16)
        Me.StatusImageList.ImageStream = CType(resources.GetObject("StatusImageList.ImageStream"), System.Windows.Forms.ImageListStreamer)
        Me.StatusImageList.TransparentColor = System.Drawing.Color.Transparent
        '
        'ProgressBar
        '
        Me.ProgressBar.Anchor = ((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left) _
                    Or System.Windows.Forms.AnchorStyles.Right)
        Me.ProgressBar.Location = New System.Drawing.Point(152, 150)
        Me.ProgressBar.Name = "ProgressBar"
        Me.ProgressBar.Size = New System.Drawing.Size(146, 20)
        Me.ProgressBar.TabIndex = 1
        '
        'message
        '
        Me.message.BackColor = System.Drawing.SystemColors.Control
        Me.message.BorderStyle = System.Windows.Forms.BorderStyle.None
        Me.message.Location = New System.Drawing.Point(8, 8)
        Me.message.Multiline = True
        Me.message.Name = "message"
        Me.message.Size = New System.Drawing.Size(304, 40)
        Me.message.TabIndex = 2
        Me.message.Text = ""
        '
        'Timer
        '
        Me.Timer.Enabled = True
        Me.Timer.Interval = 50
        '
        'StatusBar1
        '
        Me.StatusBar1.Location = New System.Drawing.Point(0, 148)
        Me.StatusBar1.Name = "StatusBar1"
        Me.StatusBar1.Panels.AddRange(New System.Windows.Forms.StatusBarPanel() {Me.infopanel, Me.statusbarpanel})
        Me.StatusBar1.ShowPanels = True
        Me.StatusBar1.Size = New System.Drawing.Size(314, 22)
        Me.StatusBar1.TabIndex = 3
        Me.StatusBar1.Text = "StatusBar1"
        '
        'infopanel
        '
        Me.infopanel.Width = 150
        '
        'statusbarpanel
        '
        Me.statusbarpanel.AutoSize = System.Windows.Forms.StatusBarPanelAutoSize.Spring
        Me.statusbarpanel.Width = 148
        '
        'updater
        '
        Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
        Me.ClientSize = New System.Drawing.Size(314, 170)
        Me.Controls.AddRange(New System.Windows.Forms.Control() {Me.ProgressBar, Me.message, Me.updatesListview, Me.StatusBar1})
        Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow
        Me.Name = "updater"
        Me.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen
        CType(Me.infopanel, System.ComponentModel.ISupportInitialize).EndInit()
        CType(Me.statusbarpanel, System.ComponentModel.ISupportInitialize).EndInit()
        Me.ResumeLayout(False)

    End Sub

#End Region

    Private WithEvents _HTTPDownloader As New codeconcepts.http_downloader
    Private _URL As String
    Private _Rename As Boolean
    Private _Version As Integer
    Private _KillProcess As String
    Private _RunApplication As String
    Private _OpenApplication As String
    Private _FilesToDownload, _FilesDownloaded As Integer

#Region "Dataset functions"

    Private Function CheckNull(ByVal Value As Object) As String
        If IsDBNull(Value) Then
            Return ""
        Else
            Return Trim(CType(Value, String))
        End If
    End Function

#End Region

#Region "Get path/filename"

    Private Function GetPath(ByVal Filename As String) As String
        ' Find the path (FOLDER) of the file
        Dim Path() As String = Split(Filename, "/")
        If UBound(Path) = 0 Then
            Return "/"
        Else
            ReDim Preserve Path(UBound(Path) - 1)
            Return "/" & Join(Path, "/")
        End If
    End Function

    Private Function GetFilename(ByVal Filename As String) As String
        ' Get the filename 
        Dim Path() As String = Split(Filename, "/")
        Return Path(UBound(Path))
    End Function

#End Region

#Region ".xml files"

    Private Sub UpdateVersion(ByVal Version As Integer)
        ' Load settings.xml and update the download version number
        Try
            Dim SettingsDataset As New DataSet()
            Dim SettingsFilename As String = Application.StartupPath & "\settings.xml"
            If IO.File.Exists(SettingsFilename) Then
                ' Read the settings XML file
                SettingsDataset.ReadXml(SettingsFilename)
                SettingsDataset.Tables("updates").Rows(0)("version") = Version
                SettingsDataset.WriteXml(SettingsFilename)
            End If
        Catch ex As Exception
            ' Display error then exit application
            MsgBox(Err.Description)
            Application.Exit()
        End Try
    End Sub

    Private Sub LoadSettings()
        Try
            Dim SettingsDataset As New DataSet()
            Dim SettingsFilename As String = Application.StartupPath & "\settings.xml"
            If IO.File.Exists(SettingsFilename) Then
                ' Read the settings XML file
                SettingsDataset.ReadXml(SettingsFilename)
                If Not SettingsDataset.Tables.Count = 0 Then
                    ' Get setup details
                    _URL = CheckNull(SettingsDataset.Tables("setup").Rows(0)("url"))
                    _KillProcess = CheckNull(SettingsDataset.Tables("setup").Rows(0)("killprocess"))
                    _RunApplication = CheckNull(SettingsDataset.Tables("setup").Rows(0)("runapplication"))
                    Me.Text = SettingsDataset.Tables("setup").Rows(0)("title")
                    ' Get the current version
                    _Version = CInt(CheckNull(SettingsDataset.Tables("updates").Rows(0)("version")))
                    ' Make sure the URL contains a / at the end.
                    If Not _URL.EndsWith("/") Then _URL += "/"
                End If
            Else
                ' Not setup file error crash updater
                MsgBox("Missing setup file", MsgBoxStyle.Critical, "Error")
                Application.Exit()
            End If
        Catch ex As Exception
            ' Display error then exit application
            MsgBox(Err.Description)
            Application.Exit()
        End Try
    End Sub

    Private Function LoadUpdates() As Integer
        Try
            Dim FilesToDownload As Integer
            Dim Fileversion As Integer
            Dim ItmX As ListViewItem
            Dim HTTPItem As codeconcepts.http_downloaderItem
            Dim updatesDataset As New DataSet()
            Dim updatesFilename As String = Application.StartupPath & "\updates.xml"
            ' Check if updates.xml exists
            If IO.File.Exists(updatesFilename) Then
                ' Read the settings XML file into dataset
                updatesDataset.ReadXml(updatesFilename)
                If updatesDataset.Tables.Contains("settings") And updatesDataset.Tables.Contains("files") Then
                    ' Get the download message from the settings table
                    message.Text = updatesDataset.Tables("settings").Rows(0)("message")
                    ' Loop through each of the files
                    Dim Row As DataRow
                    For Each Row In updatesDataset.Tables("files").Select("version > " & _Version)
                        ' Get the file version
                        Fileversion = CInt(CheckNull(Row("version")))
                        ' Create a new download item
                        HTTPItem = New codeconcepts.http_downloaderItem()
                        ' Get the URL
                        HTTPItem.DownloadURL = _URL & CheckNull(Row("filename"))
                        ' Set the folder if needed
                        If Not GetPath(Row("filename")) = "/" Then HTTPItem.Folder = GetPath(Row("filename"))
                        ' If the url exist then add the file into the download list
                        If (Not (Len(HTTPItem.DownloadURL) = 0)) Then
                            _HTTPDownloader.DownloadURLitems.Add(HTTPItem)
                            ' Update the listview
                            ItmX = updatesListview.Items.Add(GetFilename(Row("filename")))
                            ItmX.SubItems.Add(GetPath(Row("filename")))
                            ' Update the count of files
                            FilesToDownload += 1
                            ' Get the lastest update version
                            If Fileversion > _Version Then _Version = Fileversion
                        End If
                        ' Update all events running
                        Application.DoEvents()
                        _FilesToDownload = FilesToDownload
                    Next
                End If
            End If
            ' Return 0 for no files -1 for error and > 0 for amount of files
            ' in the download list
            Return FilesToDownload
        Catch ex As Exception
            ' Display error then exit application
            Console.WriteLine(ex.ToString)
            Return -1
        End Try
    End Function

#End Region

#Region "Form New/Close"

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ' Load all setting used by this updater application
        LoadSettings()
    End Sub

    Private Sub updater_Closing(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
        _HTTPDownloader.Cancel()
    End Sub

#End Region

#Region "Start downloads"

    Private Sub Timer_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer.Tick
        Try
            Application.DoEvents()
            ' Disable update running more than once
            Timer.Enabled = False
            ' Assign the progressbar to the download class
            _HTTPDownloader.ProgressBar = ProgressBar
            ' get the update file first
            _HTTPDownloader.DownloadURLitems.Add(_URL & "updates.xml")
            ' Download the master file 
            If _HTTPDownloader.Download Then
                ' Clear queue for updates
                _HTTPDownloader.DownloadURLitems.Clear()
                ' Check how many updates if there are 1 or 
                ' more download if there are 0 then display
                ' no updates message
                If LoadUpdates() = 0 Then
                    MsgBox("No updates are available at this time")
                Else
                    ' Close all processes as indicated by settings.xml
                    ' so you main app will update even if its open.
                    CloseUpdatingApplications()
                    ' Download all available updates
                    If _HTTPDownloader.Download() Then
                        ' Update settings.xml to lastest version
                        UpdateVersion(_Version)
                        MsgBox("All updates were successfull")
                        ' If a application has been specified to start 
                        'in the settings.xml then run
                        If Not Len(_RunApplication.Trim) = 0 Then Process.Start(_RunApplication)
                    End If
                End If
            End If
        Catch ex As Exception
            MsgBox(Err.Description)
        End Try
        ' Close the updater
        Application.Exit()
    End Sub

#End Region

#Region "Downloader events"

    Private Sub _HTTPDownloader_DownloadFailed(ByVal DownloadURLItem As codeconcepts.http_downloaderItem, ByVal DownloadError As String) Handles _HTTPDownloader.DownloadFailed
        ' If the download has failed place the red cross against it 
        ' in the download list
        Dim Item As ListViewItem
        For Each Item In updatesListview.Items
            If Item.Text = DownloadURLItem.Filename Then
                Item.ImageIndex = 1
            End If
        Next
        Me.Invalidate()
        _FilesDownloaded += 1
    End Sub

    Private Sub _HTTPDownloader_EndFileDownload(ByVal DownloadURLItem As codeconcepts.http_downloaderItem) Handles _HTTPDownloader.EndFileDownload
        ' If the download is successfull place the green tick against it 
        ' in the download list
        Dim Item As ListViewItem
        For Each Item In updatesListview.Items
            If Item.Text = DownloadURLItem.Filename Then
                Item.ImageIndex = 0
            End If
        Next
        Me.Invalidate()
        _FilesDownloaded += 1
    End Sub

    Private Sub _HTTPDownloader_BytesReceived(ByVal DownloadURLItem As codeconcepts.http_downloaderItem, ByVal Bytes As Integer, ByVal TotalBytes As Integer) Handles _HTTPDownloader.BytesReceived
        ' Show the status of the current file downloading in the
        ' Status panel
        If Not DownloadURLItem.Filename.ToUpper = "UPDATES.XML" Then
            infopanel.Text = "(" & _FilesDownloaded & "/" & _FilesToDownload & ") " & DownloadURLItem.Filename & " " & CInt(Bytes / 1024) & "kb / " & CInt(TotalBytes / 1024) & " kb"
        Else
            infopanel.Text = DownloadURLItem.Filename & " " & CInt(Bytes / 1024) & "kb / " & CInt(TotalBytes / 1024) & " kb"
        End If
    End Sub

#End Region

#Region "Kill processes"

    Private Sub CloseUpdatingApplications()
        ' Check the process list for any applications with 
        ' the name specified within the settings.xml and kill the 
        ' process dead!
        If Not Len(_KillProcess.Trim) = 0 Then
            Dim myProcessList As Process() = Process.GetProcessesByName("Notepad")
            Dim myProcess As Process
            For Each myProcess In myProcessList
                myProcess.Kill()
            Next
        End If
    End Sub

#End Region

End Class
